package edu.hawaii.duedates;

import java.util.ArrayList;
import java.util.List;
import com.meterware.httpunit.GetMethodWebRequest;
import com.meterware.httpunit.HttpUnitOptions;
import com.meterware.httpunit.WebConversation;
import com.meterware.httpunit.WebForm;
import com.meterware.httpunit.WebLink;
import com.meterware.httpunit.WebRequest;
import com.meterware.httpunit.WebResponse;
import com.meterware.httpunit.WebTable;

/**
 * The UserLibraryInfo Class implements the IUserLibraryInfo interface.  A user library info object
 * is comprised of a library, a user, and the validity of the request for information of this 
 * pair.  A UserLibraryInfo object has the behavior of requesting from the library the checked out
 * items for the user.
 * 
 * @author Ronn Reeves and Robin E. Raqueno
 */
public class UserLibraryInfo implements IUserLibraryInfo {
  
  /**  The collection of borrowed books.  */
  private List<Book> books;
  /**  The library receiving the request.  */
  private Library library;
  /**  The user making the request.  */
  private User user;
  /**  The validity of the request.  */
  private Boolean validity;

  
  /**
   * Creates a user library info object for this user and library.
   * 
   * @param user  The user for whom the info is being requested.
   * @param library  The library from which the info is being to requested.
   */
  public UserLibraryInfo(User user, Library library) {
    this.user = user;
    this.library = library;
    this.books = new ArrayList<Book>();
    this.validity = false;
  }


  /**
   * Sets the collection of books for this user library info request.
   * 
   * @param  books  The collection of books.
   */
  public void setBooks(List<Book> books) {
    this.books = books;
  }
  /**
   * Returns the collection of books for this user library info request.
   *
   * @return List&lt;Book&gt;  The collection of books.
   */
  public List<Book> getBooks() {
    return this.books;
  }


  /**
   * Sets this library from which the info is being requested.
   * 
   * @param  library  The library from which to request the data.
   */
  public void setLibrary(Library library) {
    this.library = library;
  }
  /**
   * Returns this library object.
   *
   * @return Library  The library providing the info.
   */
  public Library getLibrary() {
    return this.library;
  }


  /**
   * Sets this user for which the info is being requested.
   * 
   * @param  user  The user requesting the info.
   */
  public void setUser(User user) {
    this.user = user;
  }
  /**
   * Returns this user object.
   *
   * @return User  The user requesting the info.
   */
  public User getUser() {
    return this.user;
  }


  /**
   * Sets the validity of this user library info request.
   * 
   * @param  validity  The validity status of this request.
   */
  public void setValid(Boolean validity) {
    this.validity = validity;
  }
  /**
   * Returns the validity of this user library info request.  Returns true if the request is 
   * successful; false, otherwise.
   *
   * @return Boolean  The validity of the user library info request.
   */
  public Boolean isValid() {
    return this.validity;
  }


  /**
   * Returns the library name and user id of this User Library Info request.
   * 
   * @return String  The library name and user id.
   */
  public String toString() {
    return this.getLibrary().getName() + " - " + this.getUser().getUserID();
  }
  
  
  /**
   * Requests the info from this library for this user.
   */
  public void requestInfo() {
    String msgNoBorrowedItems = this.library.getNoBorrowedItemsMessage();
    this.user.setValid(true);
    this.library.setValid(true);
    this.setValid(true);

    try {
      WebConversation conversation = this.loginToLibrary();
    
      if (!(conversation == null)) {
        WebResponse response = conversation.getCurrentPage();
        
        if (!(this.library.getSummaryLink().equals(""))) {
          response = checkSummaryPage(conversation, response);
        }

        boolean processedBookTable = false;
        for (WebForm form : response.getForms()) {
          if (!(processedBookTable) && (!(msgNoBorrowedItems.equals(form.getText())))) {
            processedBookTable = processBooks(response);
          }
        }
      }
    }

    catch (Exception e) {
      this.library.setValid(false);
      this.setValid(false);
    }
  }

  
  /**
   * Returns the current page response of this web conversation.
   * 
   * @param conversation  This current web conversation.
   * @param response  The response information of this web conservation.
   * 
   * @return WebResponse  The current page response of the WebConversation.
   */
  private WebResponse checkSummaryPage(WebConversation conversation, WebResponse response) {
    try {
      for (WebLink weblink : response.getLinks()) {
        if (weblink.getText().equals(this.library.getSummaryLink())) {
          weblink.click();
        }
      }
      return conversation.getCurrentPage();
    }
    
    catch (Exception e) {
      this.library.setValid(false);
      System.out.print(e);
      return conversation.getCurrentPage(); 
      
    }
  }
  
  
  /**
   * Returns true if this web response contained a table with checked out items.  Otherwise,
   * return false if their are not currently checked out items.
   * 
   * @param response  The current web page for the current web conversation
   * 
   * @return Boolean  True if the table had checked out items; otherwise, false. 
   */
  private Boolean processBooks(WebResponse response) {
    boolean isProcessed = false;
    try {
      for (WebTable table : response.getTables()) {
        boolean isBookTable = false;
        if (table.getColumnCount() > 1) {
          int titleCol = 0;
          int dateCol = 0;
          for (int col = 0; col < table.getColumnCount(); col++) {
            if (table.getCellAsText(0, col).equals(this.library.getTitleColumn())) {
              titleCol = col;
            }
            if (table.getCellAsText(0, col).equals(this.library.getDateColumn())) {
              dateCol = col;
            }
            if (titleCol != dateCol) {
              isBookTable = true;
            }
          }

          if (isBookTable) {
            for (int row = 1; row < table.getRowCount(); row++) {
              String title = "";
              String dueDate = "";
              for (int col = 0; col < table.getColumnCount(); col++) {
                if (col == titleCol) {
                  title = table.getCellAsText(row, col).trim();  
                }
                else if (col == dateCol) {
                  dueDate = table.getCellAsText(row, col).trim();
                }
              }
              Book book = new Book(title, dueDate);
              books.add(book);
            }
            isProcessed = true;
          }
        }

        else if (table.getColumnCount() == 1) {
          if ((table.getCellAsText(0, 0).contains(this.library.getTitleColumn())) 
           && (table.getCellAsText(0, 0).contains(this.library.getDateColumn()))) {
            isBookTable = true;
          }

          if (isBookTable) {
            String delimiter = "\\|";
            String[] columns = table.getCellAsText(0, 0).split(delimiter);
            String title = "";
            String dueDate = "";
            for (int index = 0; index < columns.length; index++) {
              if (columns[index].contains(" /")) {
                title = columns[index].substring(0, columns[index].lastIndexOf('/')).trim();
                ++index;
                ++index;
                dueDate = columns[index].trim();
                Book book = new Book(title, dueDate);
                books.add(book);
              }
            }
            isProcessed = true;
          }
        }
      }
      return isProcessed;
    }
    
    catch (Exception e) {
      this.library.setValid(false);
      this.setValid(false);
      System.out.println(e);
      return isProcessed;
    }
  }
  
  
  /**
   * Logs this user into this library's web site.
   * 
   * @return conversation The results page of the library's web site after logging in.
   */
  
  private WebConversation loginToLibrary() {
    HttpUnitOptions.setExceptionsThrownOnScriptError(false);
    
    WebConversation conversation = new WebConversation();

    try {
      WebRequest request = new GetMethodWebRequest(this.library.getSiteURL());
      WebResponse response = conversation.getResponse(request);

      WebLink link = null;
      if (!(this.library.getLoginLink().equals(""))) {
        link = response.getLinkWith(this.library.getLoginLink());
        link.click();
        response = conversation.getCurrentPage();
      }

      WebForm form = null;
      if ((this.library.getFormName().equals(""))) {
        for (WebForm webForm : response.getForms()) {
          if (webForm.hasParameterNamed(this.library.getUserIdField())) {
            form = webForm;
          }
        }
      }
      else {
        form = response.getFormWithName(this.library.getFormName());
      }
      
      if ((form == null)) {
         this.library.setValid(false);
      }
      else {
        form.setParameter(this.library.getUserIdField(), this.user.getUserID());
        form.setParameter(this.library.getPasswordField(), this.user.getPassword());
        form.submit();
        response = conversation.getCurrentPage();
      }
      
      if ((!(this.library.getLoginErrorMessage().equals(""))) && 
          (response.getText().contains(this.library.getLoginErrorMessage()))) {
        this.user.setValid(false);
        this.setValid(false);
        conversation = null;
      }
    }

    catch (Exception e) {
      this.library.setValid(false);
      this.setValid(false);
      System.out.println(e);
      conversation = null;
    }
    return conversation;
  }
}